package com.duobaoyu.dby.supply.biz.service.config.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.constant.StringPool;
import com.duobaoyu.dby.common.core.service.CacheTemplate;
import com.duobaoyu.dby.common.mybatis.support.ParamConvert;
import com.duobaoyu.dby.supply.biz.converter.ChannelCallbackMappingConverter;
import com.duobaoyu.dby.supply.biz.enums.RedisKeys;
import com.duobaoyu.dby.supply.biz.service.config.ChannelCallbackMappingService;
import com.duobaoyu.dby.supply.common.biz.dto.config.ChannelCallbackMappingDTO;
import com.duobaoyu.dby.supply.common.biz.dto.config.ChannelCallbackMappingQueryDTO;
import com.duobaoyu.dby.supply.core.common.exception.CustomAssert;
import com.duobaoyu.dby.supply.db.entity.config.ChannelCallbackMapping;
import com.duobaoyu.dby.supply.db.repository.config.ChannelCallbackMappingRepository;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName ChannelCallbackMappingServiceImpl
 * @createTime 10:36:00 2023/10/16
 */
@Service
@RequiredArgsConstructor
public class ChannelCallbackMappingServiceImpl implements ChannelCallbackMappingService {

    private final CacheTemplate<String> cacheTemplate;
    private final ChannelCallbackMappingConverter channelCallbackMappingConverter;
    private final ChannelCallbackMappingRepository channelCallbackMappingRepository;

    @Override
    public String queryChannelPathMapping(String host, String channelPath) {
        return cacheTemplate.findHashCache(this.getCacheKey(host),channelPath,CommonConstants.TEN, TimeUnit.DAYS,String.class,() -> {
            ChannelCallbackMapping channelCallbackMapping = channelCallbackMappingRepository.getOne(Wrappers.<ChannelCallbackMapping>lambdaQuery()
                    .eq(ChannelCallbackMapping::getHost, host)
                    .eq(ChannelCallbackMapping::getChannelPath, channelPath)
                    .eq(ChannelCallbackMapping::getStatus, CommonConstants.ONE));
            return Optional.ofNullable(channelCallbackMapping).map(ChannelCallbackMapping::getMappingPath).orElse(StringPool.EMPTY);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createChannelPathMapping(ChannelCallbackMappingDTO channelCallbackMapping) {
        Long count = channelCallbackMappingRepository.count(Wrappers.<ChannelCallbackMapping>lambdaQuery()
                .eq(ChannelCallbackMapping::getChannelCode, channelCallbackMapping.getChannelCode())
                .eq(ChannelCallbackMapping::getChannelPath, channelCallbackMapping.getChannelPath())
                .eq(ChannelCallbackMapping::getHost,channelCallbackMapping.getHost()));
        CustomAssert.isTrue(count.compareTo(Long.valueOf(CommonConstants.ZERO)) <= CommonConstants.ZERO.intValue(),"该渠道回调路径映射已存在");
        ChannelCallbackMapping mapping = channelCallbackMappingConverter.toChannelCallbackMapping(channelCallbackMapping);
        boolean result = channelCallbackMappingRepository.save(mapping);
        channelCallbackMappingRepository.afterCommit(() -> this.removeCache(channelCallbackMapping.getHost()));
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateChannelPathMapping(ChannelCallbackMappingDTO channelCallbackMapping) {
        Long count = channelCallbackMappingRepository.count(Wrappers.<ChannelCallbackMapping>lambdaQuery()
                .eq(ChannelCallbackMapping::getChannelCode, channelCallbackMapping.getChannelCode())
                .eq(ChannelCallbackMapping::getChannelPath, channelCallbackMapping.getChannelPath())
                .eq(ChannelCallbackMapping::getHost,channelCallbackMapping.getHost())
                .ne(ChannelCallbackMapping::getId,channelCallbackMapping.getId()));
        CustomAssert.isTrue(count.compareTo(Long.valueOf(CommonConstants.ZERO)) <= CommonConstants.ZERO.intValue(),"该渠道回调路径映射已存在");
        ChannelCallbackMapping mapping = channelCallbackMappingConverter.toChannelCallbackMapping(channelCallbackMapping);
        boolean result = channelCallbackMappingRepository.updateById(mapping);
        channelCallbackMappingRepository.afterCommit(() -> this.removeCache(channelCallbackMapping.getHost()));
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteChannelPathMapping(List<Long> channelCallbackMappingIds) {
        List<ChannelCallbackMapping> channelCallbackMappings = channelCallbackMappingRepository.listByIds(channelCallbackMappingIds);
        boolean result = channelCallbackMappingRepository.removeByIds(channelCallbackMappingIds);
        Set<String> hosts = channelCallbackMappings.stream().map(ChannelCallbackMapping::getHost).collect(Collectors.toSet());
        channelCallbackMappingRepository.afterCommit(() -> this.removeCache(hosts));
        return result;
    }

    @Override
    public Page<ChannelCallbackMapping> pageChannelCallbackMapping(ChannelCallbackMappingQueryDTO channelCallbackMappingQuery) {
        LambdaQueryWrapper<ChannelCallbackMapping> queryWrapper = Wrappers.<ChannelCallbackMapping>lambdaQuery()
                .eq(StringUtils.isNotBlank(channelCallbackMappingQuery.getChannelCode()), ChannelCallbackMapping::getChannelCode, channelCallbackMappingQuery.getChannelCode())
                .eq(StringUtils.isNotBlank(channelCallbackMappingQuery.getHost()), ChannelCallbackMapping::getHost, channelCallbackMappingQuery.getHost());
        Page<ChannelCallbackMapping> page = channelCallbackMappingRepository.page(ParamConvert.getPage(channelCallbackMappingQuery), queryWrapper);
        return page;
    }

    /**
     * 获取渠道回调路径映射缓存Key
     */
    private String getCacheKey(String host) {
        return RedisKeys.CHANNEL_PATH_KEY.formatKey(host);
    }

    /**
     * 清除渠道回调路径映射缓存
     */
    public void removeCache(String host) {
        cacheTemplate.remove(this.getCacheKey(host));
    }

    public void removeCache(Set<String> hosts) {
        if(CollectionUtils.isEmpty(hosts)) {
            return;
        }
        Set<String> keys = hosts.stream().map(this::getCacheKey).collect(Collectors.toSet());
        cacheTemplate.remove(keys);
    }
}
